/******************************************************************************/
/*! 
    NDatum
    [2012]

    \NDatum.h
    \Core
    \brief      
*/
/******************************************************************************/
/*** Include guard ************************************************************/
#ifndef DATUM_H
#define DATUM_H

/*** Includes *****************************************************************/
#include "NSerializable.h"
#include <boost/numeric/ublas/matrix.hpp>

/*** Forward Declarations *****************************************************/
namespace Core
{
	class NScope;
}
/*** Namespace ****************************************************************/
namespace Core
{
/*** Macros *******************************************************************/

/*** Constants ****************************************************************/
const int BUFFER_SIZE = 100;

/*** Interface ****************************************************************/
class NDatum : public Core::NSerializable
{
	RTTI_DECLARATIONS(NDatum, NSerializable)

public:
	typedef  boost::numeric::ublas::bounded_matrix<float, 3, 3> Matrix;
	typedef  boost::numeric::ublas::bounded_vector<float, 3> Vector;

public:
	enum eType
	{
		eTYPE_UNKNOWN = -1,
		eTYPE_INT,
		eTYPE_FLOAT,
		eTYPE_STRING,
		eTYPE_DATUM,
		eTYPE_SCOPE,
		eTYPE_VECTOR,
		eTYPE_MATRIX,
		eTYPE_POINTER,
		//
		eTYPE_MAX_COUNT
	};

	union uData
	{
		int*			INT;
		float*			FLOAT;
		std::string*	STRING;
		NDatum**		DATUM;
		NScope**		SCOPE;
		Vector*			VECTOR3;
		Matrix*			MATRIX3;
		void*			POINTER;
	};
	
public:
	NDatum();

	NDatum(eType type);
	
	NDatum(const NDatum& rhs);
	
	~NDatum();
	
	void SetType(eType aType, bool overwrite = false);												 
	
	void SetNumValues(int numberOfValues);
	
	void SetFromString(const std::string& value, unsigned int index = 0,eType aType = eTYPE_UNKNOWN);
	
	void SetStorage(void* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(int* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(float* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(const std::string* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(NScope* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(NDatum* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(Vector* array, unsigned int numberOfValues, unsigned int capacity);
	
	void SetStorage(Matrix* array, unsigned int numberOfValues, unsigned int capacity);
	
	bool isExternal() const;
	
	eType GetType() const;
	
	unsigned int GetNumValues() const;
	
	unsigned int GetCapacity()  const;
	
	std::string  GetAsString( const unsigned int index = 0 );
	
	template<typename T> T& Get( unsigned int index = 0);
	
	template<typename T> T& Get( unsigned int index = 0) const;
	
	void Set(const int& value, unsigned int index = 0);
	
	void Set(const float& value, unsigned int index = 0);
	
	void Set(const std::string& value, unsigned int index = 0);
	
	void Set(const NDatum& value, unsigned int index = 0);
	
	void Set(const NScope* value, unsigned int index = 0);
	
	void Set(const Vector& value, unsigned int index = 0);
	
	void Set(const Matrix& value, unsigned int index = 0);
	
	NDatum& operator = (const NDatum& aDatum);
	
	NDatum& operator = (const int& iValue);
	
	NDatum& operator = (const float& fValue);
	
	NDatum& operator = (const std::string& sValue);
	
	NDatum& operator = (const NScope*& aValue);

	NDatum& operator = (const Vector& aValue);
	
	NDatum& operator = (const Matrix& aValue);

	bool operator == (const NDatum& aDatum) const;
	
	bool operator != (const NDatum& aDatum) const;
	
	bool operator == (const int& that)	const;

	bool operator != (const int& that)	const;
	
	bool operator == (const float& that) const;
	
	bool operator != (const float& that) const;
	
	bool operator == (const std::string& that) const; 
	
	bool operator != (const std::string& that) const;

	bool operator == (const NScope& that) const;

	bool operator != (const NScope& that) const;
	
	bool operator == (void* that) const; 
	
	bool operator != (void* that) const;
	
	bool operator == (const Vector& that) const;
	
	bool operator != (const Vector& that) const;
	
	bool operator == (const NScope* that) const;
	
	bool operator != (const NScope* that) const;
	
	bool operator == (const Matrix & that) const;
	
	bool operator != (const Matrix & that) const;
	
	static std::string StringFromType(eType aType);
	
	static eType TypeFromString(std::string aStringType);
	
	static bool	HasValue(const NDatum& aDatum,unsigned int index = 0);
	
	static bool ReferenceHasValue(const NDatum& aDatum);
	
	void Clear();
	
	void Reserve(unsigned int initialCapacity);

private:
	void InitData(int newCapacity);

	void Private_Copy(const uData & source);

	void BoundsCheck(unsigned int index) const;

private:
	unsigned int mSize;			//!< Size of array
	unsigned int mCapacity;	    //!< Capacity of array
	eType mType;				//!< Type of the datum
	uData mData;				//!< Pointer to array of type
	bool mIsExternal;			//!< Flag for type of storage
};
}
#endif//DATUM_H